package com.dcits.components.threadpools;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

@Configuration
@EnableConfigurationProperties(ThreadPoolProperties.class)
public class ThreadPoolAutoConfiguration implements InitializingBean {

    private final ThreadPoolProperties properties;
    private final ExecutorRegistry registry;
    private final Map<String, Executor> executorMap = new HashMap<>();

    @Autowired
    public ThreadPoolAutoConfiguration(ThreadPoolProperties properties, ExecutorRegistry registry) {
        this.properties = properties;
        this.registry = registry;
    }

    @Bean
    public Map<String, Executor> threadPoolMap() {
//        Map<String, Executor> executorMap = new HashMap<>();
//        properties.getConfigs().forEach((name, config) -> {
//            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//            executor.setCorePoolSize(config.getCorePoolSize());
//            executor.setMaxPoolSize(config.getMaxPoolSize());
//            executor.setQueueCapacity(config.getQueueCapacity());
//            executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
//            executor.setThreadNamePrefix(config.getThreadNamePrefix() == null ?
//                    name + "-thread-" : config.getThreadNamePrefix());
//            executor.setRejectedExecutionHandler(getRejectedPolicy(config.getRejectedExecutionHandler()));
//            executor.initialize();
//            registry.register(name, executor);
//        });
        return executorMap;
    }

    private RejectedExecutionHandler getRejectedPolicy(String name) {
        switch (name) {
            case "AbortPolicy":
                return new ThreadPoolExecutor.AbortPolicy();
            case "DiscardPolicy":
                return new ThreadPoolExecutor.DiscardPolicy();
            case "DiscardOldestPolicy":
                return new ThreadPoolExecutor.DiscardOldestPolicy();
            case "CallerRunsPolicy":
            default:
                return new ThreadPoolExecutor.CallerRunsPolicy();
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, Executor> executorMap = new HashMap<>();
        properties.getConfigs().forEach((name, config) -> {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(config.getCorePoolSize());
            executor.setMaxPoolSize(config.getMaxPoolSize());
            executor.setQueueCapacity(config.getQueueCapacity());
            executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
            executor.setThreadNamePrefix(config.getThreadNamePrefix() == null ?
                    name + "-thread-" : config.getThreadNamePrefix());
            executor.setRejectedExecutionHandler(getRejectedPolicy(config.getRejectedExecutionHandler()));
            executor.initialize();
            registry.register(name, executor);
            executorMap.put(name, executor);
        });
    }
}
